﻿//----------------------------------------------------------------
// Copyright (c) 2011-2013 
// All rights reserved.
// Author: Ben DaoWei 
// Contact: bendaowei@gmail.com
// Web Link: http://xnaeditor.codeplex.com
// ----------------------------------------------------------------


using UnityEngine.Components;
using UnityEngine.Graphics;
using System;
using UnityEngine.Primitive;
using UnityEngine.Graphics.Shader;
using UnityEngine.Graphics.Texture;
using UnityEngine.Terrain;
using UnityEngine.Graphics.Text;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using UnityEngine.Gameplay;
using UnityEngine.Audio;
namespace UnityEngine.Core
{
    public class GameScene : GameObject
    {
        public GameScene()
        {
            this.IsNeedReset = false;
        }

        public void TryToAddDebug()
        {
            foreach (GameObject g in this.Children)
                if (g.Name == "Debug")
                {
                    debug = g;
                    break;
                }

            if (debug == null)
            {
                debug = new GameObject("Debug");
                this.AddChild(debug, 0);
            }

            if (debug.HasComponent(typeof(UnityEngine.Components.DebugCamera).Name) == false)
            {
                debug.AddComponent(typeof(UnityEngine.Components.DebugCamera).Name);
            }
        }

        public void TryToAddConfiguration()
        {
            foreach (GameObject g in this.Children)
                if (g.Name == "Configuration")
                {
                    configuration = g;
                    break;
                }

            if (configuration == null)
            {
                configuration = new GameObject("Configuration");
                this.AddChild(configuration, 0);
            }

            if (configuration.HasComponent(typeof(UnityEngine.Components.Configuration).Name) == false)
            {
                configuration.AddComponent(typeof(UnityEngine.Components.Configuration).Name);
            }

            if (configuration.HasComponent(typeof(UnityEngine.Components.GameCamera).Name) == false)
            {
                configuration.AddComponent(typeof(UnityEngine.Components.GameCamera).Name);
            }

            if (configuration.HasComponent(typeof(UnityEngine.Components.GameSettings).Name) == false)
            {
                configuration.AddComponent(typeof(UnityEngine.Components.GameSettings).Name);
            }
        }

        public void Reset()
        {
            if (this.Game != null)
            {
                DebugPrimitiveRenderer.Initialize(this.Game.GraphicsDevice);
                EffectManager.Instance.ResetDevice(this.Game.GraphicsDevice);
                TextureManager.Instance.Reset();
                FontStorage.Instance.SetContent(this.Game.Content);
                AudioManager.Instance.SetContent(this.Game.Content);
                SceneManager.Instance.Initialize(this.Game);
            }
            else
            {
                throw new Exception("Game can't be null.");
            }
        }

        public override void Startup(Microsoft.Xna.Framework.GameTime gameTime)
        {
            this.Reset();
            //base.Startup(gameTime);
            Component[] all = this.GetSortedComponents();
            for (int i = 0; i < all.Length; i++)
                all[i].Startup(gameTime);
        }

        private void SolvePhysicsCollision(GameTime gameTime)
        {
            OnSurfaceObject[] objects = this.GetComponentsInChildren<OnSurfaceObject>();

            for (int i = 0; i < objects.Length; i++)
                objects[i].IsCollideWithOthers = false;
            bool findCollision = true;
            while (findCollision == true)
            {
                findCollision = false;
                for (int i = 0; i < objects.Length; i++)
                    for (int j = i + 1; j < objects.Length; j++)
                        findCollision = findCollision || OnSurfaceObject.SolveCollisions(objects[i], objects[j]);

                for (int i = 0; i < objects.Length; i++)
                    findCollision = findCollision || objects[i].SolveTerrainCollision();
            }

            for (int i = 0; i < objects.Length; i++)
                if (objects[i].IsCollideWithOthers)
                {
                    ActionObject action = objects[i].GameObject.GetComponent<ActionObject>();
                    if (action.CurrentState == ActionType.Walk.ToString())
                    {
                        action.ActionRespond = ActionRespond.Stop;
                        action.ChangeToState("Stand");
                    }
                }
        }

        public override void Update(Microsoft.Xna.Framework.GameTime gameTime)
        {
            //base.Update(gameTime);
            Component[] all = this.GetSortedComponents();

            // update physics
            Landscape landscape = this.GameScene.GetComponentInChildren<Landscape>();
            for (int i = 0; i < all.Length; i++)
                all[i].UpdatePhysics(gameTime);

            // update normal
            for (int i = 0; i < all.Length; i++)
                all[i].Update(gameTime);
            SceneManager.Instance.Update(gameTime);

            AudioManager.Instance.Update(gameTime);
            SolvePhysicsCollision(gameTime);
        }

        public override void Draw(Microsoft.Xna.Framework.GameTime gameTime)
        {
            //base.Draw(gameTime);
            Component[] all = this.GetSortedComponents();
            for (int i = 0; i < all.Length; i++)
                all[i].Draw(gameTime);
            Camera camera = null;
            switch (this.GameScene.Mode)
            {
                case SceneMode.DebugMode:
                    camera = this.GameScene.Debug.GetComponent<DebugCamera>();
                    break;
                case SceneMode.NormalMode:
                    camera = this.GameScene.Configuration.GetComponent<Camera>();
                    break;
            }

            SceneManager.Instance.Update(camera);
            SceneManager.Instance.Sort();
            SceneManager.Instance.CalculateLights(gameTime);
            EffectManager.Instance.Render();
            //SceneManager.Instance.Render();
            DebugPrimitiveRenderer.Draw(camera.View, camera.Projection);
        }

        public bool IsNeedReset
        {
            get;
            set;
        }

        private GameObject _PrefabObject = null;
        public GameObject GetPrefab(string name)
        {
            if (_PrefabObject == null)
                _PrefabObject = this.GetGameObjectInChildren("PrefabList", true);
            if (_PrefabObject != null)
            {
                var prefab = _PrefabObject.GetGameObjectInChildren(name, true);
                if (prefab != null)
                    return prefab;
            }
            throw new Exception("Prefab not found");
        }

        #region System configuration
        private GameObject configuration;
        public GameObject Configuration
        {
            get
            {
                return configuration;
            }
            set
            {
                configuration = value;
            }
        }
        #endregion

        #region Dubug
        private GameObject debug;
        public GameObject Debug
        {
            get
            {
                return debug;
            }
            set
            {
                debug = value;
            }
        }
        #endregion

        #region Mode
        private SceneMode mode;
        public SceneMode Mode
        {
            get
            {
                return mode;
            }
            set
            {
                mode = value;
            }
        }
        #endregion

        #region Game
        private UnityEngineGame game;
        public UnityEngineGame Game
        {
            get
            {
                return game;
            }
            set
            {
                game = value;
            }
        }
        #endregion

        public string Path
        {
            get;
            set;
        }
    }
}